﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing; //For Color(s) class
using System.Diagnostics;
using Microsoft.DirectX.Direct3D;
//using Microsoft.DirectX.DirectInput;

namespace DirectX_CS
{

	public class SampleStuff
	{
		Device mDevice = null;
		VertexBuffer mVertexBuffer = null;
		RV[] mRVA = null; //RV  Array of struct


		Mesh mMesh = null;


		/// <summary>
		/// Create the height data vertex by vertex.
		/// </summary>
		public RV[] CreateHeightData()
		{
			Debug.Assert(DivisionsX != 0 && DivisionsY != 0);
			float DX = (XMax - XMin) / DivisionsX;
			float DY = (YMax - YMin) / DivisionsY;

			RV[] dataVerts = new RV[EvalsX * EvalsY];

			//for vertex types with texture coordinates member.
			//float u = 0f;
			//float v = 0f;

			int index = 0;
			float y = YMin;
			float x = XMin;
			while (index < dataVerts.Length)
			{

				//now save the generated point
				float z = (float)(ScaleZ * Math.Sin(ScaleX * x) * Math.Cos(ScaleY * y));
				RV positionV = new RV(x, y, z);
				dataVerts[index] = positionV;

				if ((index + 1) % EvalsX == 0)
				{
					y += DY;
					x = XMin;
				}
				else
				{
					x += DX;
				}

				index++;
			} //end while loop

			return dataVerts;
		}

		public SampleStuff(Device deviceInUse)
		{
			mDevice = deviceInUse;
			
			mDevice.VertexFormat = RV.customVertexFormat;

			ReGenerateHeightData();
			
			//CreateBox();
		}

		public RV[] GetRVA
		{
			get { return mRVA; }
			set { mRVA = value; }
		}

		int divisionsX = 10;

		public int DivisionsX
		{
			get { return divisionsX; }
			set { divisionsX = value; }
		}
		int divisionsY = 10;

		public int DivisionsY
		{
			get { return divisionsY; }
			set { divisionsY = value; }
		}

		//int evalsX = 2;
		public int EvalsX
		{
			get { return divisionsX + 1; }
			//set { evalsX = value; }
		}
		float xMin = -10, xMax = 10;
		public float XMin
		{
			get { return xMin; }
			set { xMin = value; }
		}
		public float XMax
		{
			get { return xMax; }
			set { xMax = value; }
		}

		public int EvalsY
		{
			get { return divisionsY + 1; }
			//set { evalsY = value; }
		}

		float yMin = -10, yMax = 10;
		public float YMax
		{
			get { return yMax; }
			set { yMax = value; }
		}
		public float YMin
		{
			get { return yMin; }
			set { yMin = value; }
		}

		public void ReGenerateHeightData()
		{
			mRVA = CreateHeightData();
			CreateVertexBuffer(); //and sets it no need to call Reset
		}

		float mScaleZ = 1.0f;

		private float scaleX = 1.0f;

		public float ScaleX
		{
			get { return scaleX; }
			set { scaleX = value; }
		}
		private float scaleY = 1.0f;

		public float ScaleY
		{
			get { return scaleY; }
			set { scaleY = value; }
		}

		public float ScaleZ
		{
			get { return mScaleZ; }
			set { mScaleZ = value; }
		}

		public void CreateBox()
		{
			//mMesh = Mesh.Cylinder(mDevice, 1f, 1f, 1f, 10, 10);
			mMesh = Mesh.Box(mDevice, 2f, 2f, 2f);
			//mMesh = Mesh.Teapot(mDevice);

			AttributeRange ar = new AttributeRange();
			ar.AttributeId = 0;
			ar.FaceStart = 0;
			ar.FaceCount = mMesh.NumberFaces;
			ar.VertexStart = 0;
			ar.VertexCount = mMesh.NumberVertices;
			mMesh.SetAttributeTable(new AttributeRange[] { ar });

		}
		public void DrawMesh()
		{
			if (mMesh != null)
			{
				AttributeRange[] ar = mMesh.GetAttributeTable();
				int numSubSets = ar.Length;

				for (int i = 0; i < numSubSets; ++i)
				{
					mMesh.DrawSubset(i);
				}
			}
		}

		public void DrawStuff()
		{

		#region "Old Code"
			//int stVertex = 0; //doesnt make sense why it doesnt use managed
			//mDevice.DrawPrimitives(PrimitiveType.PointList, stVertex, primitiveCount );
			//mDevice.DrawUserPrimitives(PrimitiveType.PointList, primitiveCount, mVertexBuffer);
			//DrawCylinderMeshSample();

			//try to do what its doing
			//Type typeSize = typeof(RV);
			
			//int iArraySizeWONder = Microsoft.DirectX.DXHelp.GetTypeSize(mRVA.GetType()); //FAILS PROBABLY WHAT ITS CHOKING ON
			//int iArraySizeWONder = Microsoft.DirectX.DXHelp.GetTypeSize(mRVA.GetType()); //FAILS PROBABLY WHAT ITS CHOKING ON
			//int iArraySizeWONder = Microsoft.DirectX.DXHelp.GetTypeSize(mRVA.GetType()); //FAILS PROBABLY WHAT ITS CHOKING ON

			//int iElementSizeWON = Microsoft.DirectX.DXHelp.GetTypeSize(mRVA[0].GetType());
			//int iWorks = Microsoft.DirectX.DXHelp.GetObjectSize(mRVA);
			//I guess it seems to me that drawuserprimitives is messed.
			//mDevice.DrawUserPrimitives(PrimitiveType.PointList, primitiveCount, mVertexBuffer); //was drawing RVA

			//int vertexStart = 0;
			//draw primitives 
			//int primitiveCount = VertexCount;
			//mDevice.DrawPrimitives(PrimitiveType.PointList, vertexStart, primitiveCount); //was drawing mRVA WHICH WAS AN ERROR
#endregion "Old Code"

			//DrawMesh();

			//WORKING CODE
			//WORKING CODE
			for (int rowIdx = 0; rowIdx < EvalsY; rowIdx++)
			{
				int vertexStart = rowIdx * EvalsX;
				mDevice.DrawPrimitives(PrimitiveType.LineStrip, vertexStart, EvalsX - 1); //was drawing mRVA WHICH WAS AN ERROR
			}
			//mDevice.DrawUserPrimitives(PrimitiveType.LineStrip,  VertexCount - 1, 0); 			//allows user to set stream
			//WORKING CODE

		}


		private void CreateVertexBuffer()
		{
			mVertexBuffer = new VertexBuffer(mRVA[0].GetType(), VerticesCount, mDevice, Usage.Points, RV.customVertexFormat, Pool.Managed);
			int lockOffset = 0;
			//now Set the buffer data..
			//set data it seems immediately before calls to lock
			mVertexBuffer.SetData(mRVA, lockOffset, LockFlags.ReadOnly);

			//ONE IMPORTANT PART IS SETTING THE STREAM SOURCE...
			int streamNumber = 0;
			int offsetInBytes = 0;
			mDevice.SetStreamSource(streamNumber, mVertexBuffer, offsetInBytes);

			VertexElement[] v = new VertexElement[] 
			{ 
				new VertexElement(0,0,DeclarationType.Float3,DeclarationMethod.Default,
					DeclarationUsage.Position,0),
				/*new VertexElement(0,12,DeclarationType.Float3,DeclarationMethod.Default,
					DeclarationUsage.Normal,0),
				new VertexElement(0,24,DeclarationType.Float2,DeclarationMethod.Default,
					DeclarationUsage.TextureCoordinate,0),
				new VertexElement(0,32,DeclarationType.Float4,DeclarationMethod.Default,
					DeclarationUsage.TextureCoordinate,1), 
				 */
				VertexElement.VertexDeclarationEnd
			};

			VertexDeclaration decl = new VertexDeclaration(mDevice, v);
			//Type T = typeof(RV);
			//Usage U = Usage.Points; //usage can be zero(Usage.None)-see tooltip of constructor, loaded from meta data comments.
			//Pool P = Pool.Managed;//maybe pool managed?
			
			//Something doesnt make sense about the vertex buffer, its managed therefore its type should be able to be reflected

			//mVertexBuffer = new VertexBuffer(T, VerticesCount, mDevice, U, RV.customVertexFormat, P);
			//one alternative, because i have a feeling the vertexbuffer is lame.
			//int sizeOfBufferInBytes = System.Runtime.InteropServices.Marshal.SizeOf(RVA) * RVA.Length;//System.Runtime.InteropServices.Marshal.SizeOf(RVA);
			//int sizeOfBSBuf = 0;
			//int lockAtOffset = 0;
			//mVertexBuffer.SetData(mRVA, lockAtOffset, LockFlags.ReadOnly);

		}

		private void ReSetVBData()
		{
			int lockOffset = 0;
			mVertexBuffer.Unlock(); //use the 3 parameter form not the two so you dont accidentall uwe the lockflag as an offset
			mVertexBuffer.SetData(mRVA, lockOffset, LockFlags.ReadOnly);
			mVertexBuffer.Lock(lockOffset, 0, LockFlags.ReadOnly);
		}

		private int VertexCount
		{
			get { return mRVA.Length; }
		}
		private int VerticesCount
		{
			get { return mRVA.Length; }
		}
	}

	public struct RV
	{
		public float X;
		public float Y;
		public float Z;
		//public float rhw;
		//public float tu;
		//public float tv;
		//public RV(float x, float y, float z, float w, float u, float v)
		//{
		//	X = x; Y = y; Z = z; rhw = w; tu = u; tv = v;
		//}
		public RV(float x, float y, float z)
		{
			X = x; Y = y; Z = z; //rhw = 0; tu = 0; tv = 0;
		}
		public const VertexFormats customVertexFormat =
			VertexFormats.Position ;

	}
}

